package com.xindacloud.sms.adapter.component;

import com.clxcommunications.xms.api.BatchDeliveryReport;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.xindacloud.sms.adapter.bo.DomesticSmsReportRequestBodyBO;
import com.xindacloud.sms.adapter.bo.HuoxinReportDataBO;
import com.xindacloud.sms.adapter.dto.IncomingSMSDlrPayloadDTO;
import com.xindacloud.sms.adapter.entity.SmsDeliveryReceipt;
import com.xindacloud.sms.adapter.entity.SmsErrorCode;
import com.xindacloud.sms.adapter.service.business.ISmsErrorCodeService;
import com.xindacloud.sms.adapter.utils.AgentEnum;
import com.xindacloud.sms.adapter.utils.DateHelp;
import com.xindacloud.sms.adapter.utils.MappingStatusHelp;
import com.xindacloud.sms.adapter.utils.StatusEum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.*;

import static com.xindacloud.sms.adapter.utils.DateHelp.*;

@Slf4j
@Component
public class ReceiveDLRConvertComponent {


    @Autowired
    ISmsErrorCodeService errorCodeService;

    @NotNull
    public SmsDeliveryReceipt getNexmoReceiveDLRDTO(HttpServletRequest req) {

        try {
            Map<String, String> dlrResult = new HashMap<>();
            for (String param : Collections.list(req.getParameterNames())) {
                dlrResult.put(param, req.getParameter(param));
            }
            IncomingSMSDlrPayloadDTO incomingSMSDlrPayloadDTO = IncomingSMSDlrPayloadDTO.fromJson(new Gson().toJson(dlrResult).getBytes());
            LocalDateTime messageTimestamp = LocalDateTime.now();
            if (Objects.nonNull(incomingSMSDlrPayloadDTO.getMessageTimestamp())) {
                messageTimestamp = str2LocalDateTimePlusHours(incomingSMSDlrPayloadDTO.getMessageTimestamp(), Y_M_D_H_M_S_PATTERN, 8);
            }
            log.info("Nexmo incomingSMSDlrPayloadDTO:{}", incomingSMSDlrPayloadDTO.toString());
            return SmsDeliveryReceipt.builder()
                    .errorCode(incomingSMSDlrPayloadDTO.getErrCode())
                    .reason(getErrorReason(AgentEnum.NEXMO_AGENT.getAgentName(), incomingSMSDlrPayloadDTO.getErrCode()))
                    .messageId(incomingSMSDlrPayloadDTO.getMessageId())
                    .networkCode(incomingSMSDlrPayloadDTO.getNetworkCode())
                    .sentFrom(incomingSMSDlrPayloadDTO.getTo())
                    .sentTo(incomingSMSDlrPayloadDTO.getMsisdn())
                    .scts(incomingSMSDlrPayloadDTO.getScts())
                    .messageTimestamp(messageTimestamp)
                    .status(incomingSMSDlrPayloadDTO.getStatus().toLowerCase())
                    .price(new BigDecimal(incomingSMSDlrPayloadDTO.getPrice()))
                    .build();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;

    }

    private String getErrorReason(String errorType, String errorCode) {
        log.info("query error reason params:errorType:{},errorCode:{}", errorType, errorCode);
        if (Objects.equals("0", errorCode)) {
            return "";
        }
        final SmsErrorCode error = errorCodeService.querySmsErrorCodeByErrorTypeAndErrorCode(errorType, errorCode);
        log.info("query error result:{}", new Gson().toJson(error));
        return Objects.nonNull(error) ? (Objects.nonNull(error.getCustomReason()) ? error.getCustomReason() : error.getReason()) : "Unknown";
    }


    @NotNull
    public List<SmsDeliveryReceipt> getSinchReceiveDLRDTO(BatchDeliveryReport report) {
        log.info("Sinch Receive DLR:{}", new Gson().toJson(report));
        List<SmsDeliveryReceipt> deliveryReceiptList = new ArrayList<>();
        final List<BatchDeliveryReport.Status> statuses = report.statuses();
        for (BatchDeliveryReport.Status status : statuses) {
            for (String sendTo : status.recipients()) {
                SmsDeliveryReceipt.SmsDeliveryReceiptBuilder builder = SmsDeliveryReceipt.builder();
                builder.messageId(report.batchId().toString());
                builder.sentTo(sendTo);
                builder.messageTimestamp(LocalDateTime.now());
                builder.errorCode(String.valueOf(status.code()));
                builder.status(StringUtils.isNotEmpty(status.status().status()) ? status.status().status().toLowerCase() : "");
                builder.reason(getErrorReason(AgentEnum.SINCH_AGENT.getAgentName(), String.valueOf(status.code())));
                builder.messageCount(report.totalMessageCount());
                deliveryReceiptList.add(builder.build());
            }
        }
        return deliveryReceiptList;

    }


    @NotNull
    public SmsDeliveryReceipt getCMReceiveDLRDTO(HttpServletRequest req) {

        try {
            log.info("### CM delivery-receipt parameter map:{}", new Gson().toJson(req.getParameterMap()));
            final String messageId = req.getParameter("REFERENCE");
            final String statusCode = req.getParameter("STATUS");
            final String statusName = MappingStatusHelp.CmMessageStatus.fromInt(Integer.parseInt(statusCode)).toString();
            LocalDateTime messageTimestamp = LocalDateTime.now();
            if (Objects.nonNull(req.getParameter("DATETIME_S"))) {
                messageTimestamp = str2LocalDateTimePlusHours(req.getParameter("DATETIME_S"), Y_M_D_T_H_M_S_PATTERN, 7);
            }
            final String gsm = req.getParameter("GSM");
            final String sentTo = (gsm.startsWith("00") ? gsm.substring(2) : gsm);
            return SmsDeliveryReceipt.builder()
                    .errorCode(statusCode)
                    .messageId(messageId)
                    .networkCode(req.getParameter("OPERATOR"))
                    .sentTo(sentTo)
                    .scts(DateHelp.localDateTime2Str(str2LocalDateTimePlusHours(req.getParameter("CREATED_S"), Y_M_D_T_H_M_S_PATTERN, 7)))
                    .messageTimestamp(messageTimestamp)
                    .status(StringUtils.isNotEmpty(statusName) ? statusName.toLowerCase() : "")
                    .price(BigDecimal.ZERO)
                    .reason(getErrorReason(AgentEnum.CM_AGENT.getAgentName(), statusCode))
                    .build();
        } catch (DateTimeParseException | NumberFormatException e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }


    @NotNull
    public SmsDeliveryReceipt getDomesticReceiveDLRDTO(DomesticSmsReportRequestBodyBO reportRequestBodyBO) {

        try {
            log.info("### 国内 delivery-receipt parameter map:{}", new Gson().toJson(reportRequestBodyBO));
            final String messageId = reportRequestBodyBO.getUuid();
            final String sentTo = reportRequestBodyBO.getDest_number();
            final String error_code = reportRequestBodyBO.getError_code();
            LocalDateTime messageTimestamp = LocalDateTime.now();
            if (Objects.nonNull(reportRequestBodyBO.getTimestamp())) {
                messageTimestamp = str2LocalDateTimePlusHours(reportRequestBodyBO.getTimestamp(), Y_M_D_H_M_S_PATTERN, 0);
            }

            //"delivered" : "failed"
            return SmsDeliveryReceipt.builder()
                    .errorCode(reportRequestBodyBO.getSuccess() ? "0" : error_code)
                    .messageId(messageId)
                    .sentTo(sentTo)
                    .scts(DateHelp.localDateTime2Str(str2LocalDateTimePlusHours(reportRequestBodyBO.getReport_time(), Y_M_D_H_M_S_PATTERN, 0)))
                    .messageTimestamp(messageTimestamp)
                    .status(reportRequestBodyBO.getSuccess() ? StatusEum.DELIVERED.desc : reportRequestBodyBO.getError_code().toLowerCase())
                    .price(BigDecimal.ZERO)
                    //.networkCode(reportRequestBodyBO.getNetwork())
                    .reason(reportRequestBodyBO.getSuccess() ? "" :
                            Objects.nonNull(reportRequestBodyBO.getError_message())
                                    ? reportRequestBodyBO.getError_code() : getErrorReason(AgentEnum.DOMESTIC_AGENT.getAgentName(), error_code))
                    .build();
        } catch (DateTimeParseException | NumberFormatException e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }


    @NotNull
    public List<SmsDeliveryReceipt> getHuoxinReceiveDLRDTO(HttpServletRequest request) {
        String data = "";
        List<SmsDeliveryReceipt> list = new ArrayList<>();
        try {
            InputStream inputStream = request.getInputStream();
            byte[] tmp = readInputStream(inputStream);
            data = new String(tmp, "utf-8");
            log.info("火信云回执报告参数: {}", data);
            List<HuoxinReportDataBO> reports = new Gson().fromJson(data, new TypeToken<List<HuoxinReportDataBO>>(){}.getType());
            for (HuoxinReportDataBO huoxinReportDataBO : reports) {
                SmsDeliveryReceipt huoxinReceiveDLRDTO = SmsDeliveryReceipt.builder()
                        .errorCode(huoxinReportDataBO.getCode())
                        .messageId(huoxinReportDataBO.getTaskid())
                        .reason(huoxinReportDataBO.getMsg().equals("成功") ? "" : huoxinReportDataBO.getMsg())
                        .sentTo(huoxinReportDataBO.getMobile())
                        .status(huoxinReportDataBO.getCode().equals("DELIVRD") ? "delivered" : huoxinReportDataBO.getCode().toLowerCase())
                        .price(BigDecimal.ZERO)
                        .messageTimestamp(LocalDateTime.now())
                        .scts(DateHelp.localDateTime2Str(DateHelp.str2LocalDateTimePlusHours(huoxinReportDataBO.getTime(), DateHelp.YMDHMS_PATTERN, 0)))
                        .build();
                list.add(huoxinReceiveDLRDTO);
            }
        }catch(Exception e){
            log.error(e.getMessage(), e);
        }
        return list;
    }


    private byte[] readInputStream(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        boolean var3 = false;

        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }

        outSteam.close();
        inputStream.close();
        return outSteam.toByteArray();
    }


}
